package com.joker.aigc.chat.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.joker.aigc.chat.dao.ContactDao;
import com.joker.aigc.chat.domain.dto.MessageDto;
import com.joker.aigc.chat.domain.dto.MessageMemberDto;
import com.joker.aigc.chat.domain.dto.MessageQueryCriteria;
import com.joker.aigc.chat.domain.dto.MessageReadDto;
import com.joker.aigc.chat.domain.dto.MessageReadInfoCriteria;
import com.joker.aigc.chat.domain.dto.MessageRecallDto;
import com.joker.aigc.chat.domain.entity.Contact;
import com.joker.aigc.chat.domain.entity.Message;
import com.joker.aigc.chat.domain.enums.MessageStatusEnum;
import com.joker.aigc.chat.domain.enums.MessageTypeEnum;
import com.joker.aigc.chat.domain.mapstruct.MessageMapstruct;
import com.joker.aigc.chat.domain.vo.MessageReadInfoVo;
import com.joker.aigc.chat.domain.vo.MessageReadVo;
import com.joker.aigc.chat.domain.vo.MessageVo;
import com.joker.aigc.chat.mapper.MessageMapper;
import com.joker.aigc.chat.mapper.RoomFriendMapper;
import com.joker.aigc.chat.mapper.RoomGroupMapper;
import com.joker.aigc.chat.mapper.RoomMapper;
import com.joker.aigc.chat.service.MessageService;
import com.joker.aigc.chat.service.event.MessageSendEvent;
import com.joker.aigc.chat.service.strategy.AbstractMsgHandler;
import com.joker.aigc.chat.service.strategy.MsgHandlerFactory;
import com.joker.aigc.dao.UserDao;
import com.joker.aigc.domain.entity.User;
import com.joker.aigc.domain.enums.RoleEnum;
import com.joker.aigc.mapper.UserMapper;
import com.joker.aigc.service.UserRoleService;
import com.joker.aigc.utils.AssertUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author 20346
 * @description 针对表【message(消息表)】的数据库操作Service实现
 * @createDate 2023-12-17 11:26:08
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class MessageServiceImpl extends ServiceImpl<MessageMapper, Message> implements MessageService {


    final RoomMapper roomMapper;
    final RoomFriendMapper roomFriendMapper;
    final UserMapper userMapper;
    final RoomGroupMapper roomGroupMapper;

    final ApplicationEventPublisher applicationEventPublisher;
    final MessageMapstruct messageMapstruct;
    final UserRoleService userRoleService;
    final ContactDao contactDao;
    final UserDao userDao;

    @Override
    public MessageVo sendMsg(MessageDto request, Long uid) {

        // 解析消息，并将消息存在数据库中 message库中
        AbstractMsgHandler<?> msgHandler = MsgHandlerFactory.getStrategyNoNull(request.getMsgType());
        Message message = msgHandler.checkAndSaveMsg(request, uid);
        MessageVo messageVo = messageMapstruct.toVO(message);
        User user = userMapper.selectById(uid);
        messageVo.setAvatar(user.getAvatar());
        messageVo.setUsername(user.getUsername());

        //发布消息发送事件
        applicationEventPublisher.publishEvent(new MessageSendEvent(this, message));
        return messageVo;
    }

    @Override
    public MessageVo queryMessageById(Long msgId) {
        return null;
    }

    /**
     * 获取该房间的 所有消息
     *
     * @param criteria 查询条件
     * @return 该房间的 所有消息
     */
    @Override
    public Page<MessageVo> queryMessage(MessageQueryCriteria criteria) {

        MPJLambdaWrapper<Message> wrapper = new MPJLambdaWrapper<>();
        // 根据时间 从 现在 到 以前 降序排序。

        wrapper.selectAll(Message.class)
                .select(User::getUsername, User::getAvatar)
                .leftJoin(User.class, User::getId, Message::getFromUid)
                .eq(Message::getRoomId, criteria.getRoomId())
                .orderByDesc(Message::getCreateTime);
        Page<MessageVo> page = getBaseMapper().selectJoinPage(new Page<MessageVo>(criteria.getPageNum(), criteria.getPageSize()), MessageVo.class, wrapper);
        List<MessageVo> pageList = page.getRecords();
        page.setRecords(pageList);
        return page;
    }

    @Override
    public void recallMsg(MessageRecallDto recallDto) {

    }


    private void checkRecall(Long uid, Message message) {
        AssertUtil.isNotEmpty(message, "消息有误");
        AssertUtil.notEqual(message.getType(), MessageTypeEnum.RECALL.getType(), "消息无法撤回");
        boolean hasPower = userRoleService.hasPower(uid, RoleEnum.CHAT_MANAGER);
        if (hasPower) {
            return;
        }
        boolean self = Objects.equals(uid, message.getFromUid());
        AssertUtil.isTrue(self, "抱歉,您没有权限");
        long between = DateUtil.between(message.getCreateTime(), new Date(), DateUnit.MINUTE);
        AssertUtil.isTrue(between < 2, "覆水难收，超过2分钟的消息不能撤回哦~~");
    }

    /**
     * @param uid     用户id
     * @param request 获取消息的已读未读列表
     * @return
     */
    @Override
    public Page<MessageReadVo> getReadPage(Long uid, MessageReadDto request) {

        Message message = getById(request.getMsgId());
        AssertUtil.isNotEmpty(message, "消息id有误");
        AssertUtil.equal(uid, message.getFromUid(), "只能查看自己的消息");

        Page<Contact> page;
        Page<Contact> contactPage = new Page<>(request.getPageNum(), request.getPageSize());
        if (request.getSearchType() == 1) {
            page = contactDao.getReadPage(message, contactPage);
        } else {
            page = contactDao.getUnReadPage(message, contactPage);
        }
        List<Contact> list = page.getRecords();
        List<MessageReadVo> collect = list.stream().map(contact -> {
            MessageReadVo resp = new MessageReadVo();
            resp.setUid(contact.getUid());
            return resp;
        }).collect(Collectors.toList());

        Page<MessageReadVo> result = new Page<>(page.getCurrent(), page.getSize(), page.getSize());
        result.setRecords(collect);
        return result;

//        CursorPageBaseResp<Contact> page;
//        if (request.getSearchType() == 1) {//已读
//            page = contactDao.getReadPage(message, request);
//        } else {
//            page = contactDao.getUnReadPage(message, request);
//        }
//        if (CollectionUtil.isEmpty(page.getList())) {
//            return CursorPageBaseResp.empty();
//        }
//        return CursorPageBaseResp.init(page, RoomAdapter.buildReadResp(page.getList()));
    }

    @Override
    public List<MessageReadInfoVo> getReadInfo(Long uid, MessageReadInfoCriteria request) {
        List<Message> messages = listByIds(request.getMsgIds());
        messages.forEach(message -> {
            AssertUtil.equal(uid, message.getFromUid(), "只能查询自己发送的消息");
        });
        return (List<MessageReadInfoVo>) contactDao.getMsgReadInfo(messages).values();
    }

    /**
     * 读取消息
     *
     * @param uid     用户uid
     * @param request
     */
    @Override
    public void msgRead(Long uid, MessageMemberDto request) {
        Contact contact = contactDao.get(uid, request.getRoomId());
        if (Objects.nonNull(contact)) {
            Contact update = new Contact();
            update.setId(contact.getId());
            update.setReadTime(new Date());
            contactDao.updateById(update);
        } else {
            Contact insert = new Contact();
            insert.setUid(uid);
            insert.setRoomId(request.getRoomId());
            insert.setReadTime(new Date());
            contactDao.save(insert);
        }
    }

//    public void check(MessageDto request, Long uid) {
//
//        // 开始校验
//        Long roomId = request.getRoomId();
//        // 首先判断 roomId是否存在
//        Room room = roomMapper.selectById(roomId);
//        // 如果房间不存在
//        AssertUtil.isNotEmpty(room, AppHttpCodeEnum.ROOM_NOT_EXIST);
//
//    }


    public boolean riseOptimistic(Long id, Integer oldType, Integer newType) {
        return lambdaUpdate()
                .eq(Message::getId, id)
                .eq(Message::getType, oldType)
                .set(Message::getType, newType)
                .update();
    }

    public Integer getGapCount(Long roomId, Long fromId, Long toId) {
        return Math.toIntExact(lambdaQuery()
                .eq(Message::getRoomId, roomId)
                .gt(Message::getId, fromId)
                .le(Message::getId, toId)
                .count());
    }

    public void invalidByUid(Long uid) {
        lambdaUpdate()
                .eq(Message::getFromUid, uid)
                .set(Message::getStatus, MessageStatusEnum.DELETE.getStatus())
                .update();
    }


    public Integer getUnReadCount(Long roomId, Date readTime) {
        // 获取消息。当时间
        return Math.toIntExact(lambdaQuery()
                .eq(Message::getRoomId, roomId)
                .gt(Objects.nonNull(readTime), Message::getCreateTime, readTime)
                .count());
    }

    public Boolean removeByRoomId(Long roomId, List<Long> uidList) {
        if (CollectionUtil.isNotEmpty(uidList)) {
            LambdaUpdateWrapper<Message> wrapper = new UpdateWrapper<Message>().lambda()
                    .eq(Message::getRoomId, roomId)
                    .in(Message::getFromUid, uidList)
                    .set(Message::getStatus, MessageStatusEnum.DELETE.getStatus());
            return this.update(wrapper);
        }
        return false;
    }


}




